package org.jhouse.test.cli.impl;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.jboss.as.cli.CliInitializationException;
import org.jboss.as.cli.CommandContext;
import org.jboss.as.cli.CommandContextFactory;
import org.jboss.as.cli.CommandFormatException;
import org.jboss.as.cli.CommandLineException;
import org.jboss.as.cli.Util;
import org.jboss.as.controller.client.ModelControllerClient;
import org.jboss.as.protocol.StreamUtils;
import org.jboss.dmr.ModelNode;
import org.tmatesoft.svn.core.SVNProperties;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager;
import org.tmatesoft.svn.core.io.SVNRepository;
import org.tmatesoft.svn.core.io.SVNRepositoryFactory;
import org.tmatesoft.svn.core.wc.SVNWCUtil;

/**
 * 
 * @author <a href="mailto:ljhiyh@gmail.com">Jooho Lee, Jay</a>
 */

public class CLIBLauncher {

	/**
	 * <pre>
	 * Description : Launcher Main
	 * 
	 * @Author : Jooho Lee, Jay
	 * @Method Name : main
	 * @param args
	 */

	public static void main(String[] args) throws Exception {
		int exitCode = 0;
		CommandContext cmdCtx = null;
		String defaultControllerHost = "10.144.97.99";
		int defaultControllerPort = 9999;
		File inputFile = null;
		File outputFile = null;
		List<String> commands = new ArrayList<String>();
		String argError = null;
		int periodSec = 0;
		int executeCount = 1;
		String user = "jboss";
		char[] password = "jboss1234!@#$".toCharArray();
		boolean isOutput = false;
		BufferedWriter output = null;
		Date now = new Date();

		final String svnURL = "http://10.144.136.56/svndps_test/dpssvn01/";
		final String svnUSR = "dpssvn01";
		final String svnPWD = "abcd1234";
		final String fileName = "sysflow2.war";
		final String relativePath = "";
		final long ver = 176;

		final ByteArrayOutputStream baos = new ByteArrayOutputStream();
		final SVNRepository repo = SVNRepositoryFactory.create(SVNURL.parseURIEncoded(svnURL));
		final ISVNAuthenticationManager authManager = SVNWCUtil.createDefaultAuthenticationManager(svnUSR, svnPWD);
		repo.setAuthenticationManager(authManager);

		try {

			repo.getRepositoryPath(""); // 執行查詢相關路徑位址，以驗證連結成功
			repo.getFile(relativePath + fileName, ver, new SVNProperties(), baos);

			OutputStream outputStream = new FileOutputStream(fileName);
			baos.writeTo(outputStream);


			//commands.add("deploy " + fileName + " --force");
			//commands.add("deploy " + fileName + " --server-groups=main-server-group");
			commands.add("deploy " + fileName + " --all-server-groups");
			//commands.add("undeploy " + fileName + " --all-relevant-server-groups");
			//commands.add("undeploy " + fileName + " --keep-content --server-groups=main-server-group");
			//commands.add("undeploy " + fileName + " --server-groups=other-server-group");
			for (String arg : args) {
				if (arg.startsWith("--controller=")
						|| arg.startsWith("controller=")) {
					final String fullValue;
					final String value;
					if (arg.startsWith("--")) {
						fullValue = arg.substring(13);
					} else {
						fullValue = arg.substring(11);
					}
					final int protocolEnd = fullValue.lastIndexOf("://");
					if (protocolEnd == -1) {
						value = fullValue;
					} else {
						value = fullValue.substring(protocolEnd + 3);
					}

					String portStr = null;
					int colonIndex = value.lastIndexOf(':');
					if (colonIndex < 0) {
						// default port
						defaultControllerHost = value;
					} else if (colonIndex == 0) {
						// default host
						portStr = value.substring(1);
					} else {
						final boolean hasPort;
						int closeBracket = value.lastIndexOf(']');
						if (closeBracket != -1) {
							// possible ip v6
							if (closeBracket > colonIndex) {
								hasPort = false;
							} else {
								hasPort = true;
							}
						} else {
							// probably ip v4
							hasPort = true;
						}
						if (hasPort) {
							defaultControllerHost = value.substring(0,
									colonIndex).trim();
							portStr = value.substring(colonIndex + 1).trim();
						} else {
							defaultControllerHost = value;
						}
					}

					if (portStr != null) {
						int port = -1;
						try {
							port = Integer.parseInt(portStr);
							if (port < 0) {
								argError = "The port must be a valid non-negative integer: '"
										+ args + "'";
							} else {
								defaultControllerPort = port;
							}
						} catch (NumberFormatException e) {
							argError = "The port must be a valid non-negative integer: '"
									+ arg + "'";
						}
					}
				} else if (arg.startsWith("--f=") || arg.startsWith("f=")) {
					if (inputFile != null) {
						argError = "Duplicate argument '--f'.";
						break;
					}
					if (commands != null) {
						argError = "Only one of '--f', '--commands' or '--command' can appear as the argument at a time.";
						break;
					}

					final String inputFileName = arg.startsWith("--") ? arg
							.substring(4) : arg.substring(2);
					if (!inputFileName.isEmpty()) {
						inputFile = new File(inputFileName);
						if (!inputFile.exists()) {
							argError = "File " + inputFile.getAbsolutePath()
									+ " doesn't exist.";
							break;
						}
						commands = processFile(inputFile, cmdCtx);

					} else {
						argError = "Argument '--f' is missing value.";
						break;
					}
				} else if (arg.startsWith("--o=") || arg.startsWith("--o")) {
					final String outputFileName = arg.indexOf("=") > 0 ? arg
							.substring(4) : arg.substring(3);
					isOutput = true;
					if (!outputFileName.isEmpty()) {
						outputFile = new File(outputFileName);
						if (!outputFile.exists()) {
							argError = "File " + outputFile.getAbsolutePath()
									+ " doesn't exist.";
							break;
						}

					} else {
						outputFile = new File("CLIB_output.txt");
					}
				} else if (arg.startsWith("--commands=")
						|| arg.startsWith("commands=")) {
					if (inputFile != null) {
						argError = "Only one of '--f', '--commands' or '--command' can appear as the argument at a time.";
						break;
					}
					if (commands != null) {
						argError = "Duplicate argument '--command'/'--commands'.";
						break;
					}
					final String value = arg.startsWith("--") ? arg
							.substring(11) : arg.substring(9);
					commands = new ArrayList<String>();
					commands = Util.splitCommands(value); // for list
				} else if (arg.startsWith("--user=")) {
					user = arg.startsWith("--") ? arg.substring(7) : arg
							.substring(5);
				} else if (arg.startsWith("--password=")) {
					password = (arg.startsWith("--") ? arg.substring(11) : arg
							.substring(9)).toCharArray();
				} else if (arg.startsWith("--p=")) {
					periodSec = Integer.parseInt((arg.startsWith("--") ? arg
							.substring(4) : arg.substring(2)));
				} else if (arg.startsWith("--c=")) {
					executeCount = Integer.parseInt((arg.startsWith("--") ? arg
							.substring(4) : arg.substring(2)));
				}
			}

			if (argError != null) {
				System.err.println(argError);
				exitCode = 1;
				return;
			}
			System.out.println("CLIB Info: (" + now + ")");
			System.out
					.println("---------------------------------------------------------------------");
			System.out.println("* EAP Server IP : " + defaultControllerHost
					+ ":" + defaultControllerPort);
			System.out.println("* User name : " + user);
			System.out.println("* Period : " + periodSec + " Sec");
			System.out.println("* Total Cycle : " + executeCount);
			System.out.println("* Execute CLI Commands Count: "
					+ commands.size());
			System.out
					.println("=======================Each Command=================================");
			for (String command : commands) {
				System.out.println(command);
			}
			System.out
					.println("=======================Each Command=================================");
			System.out
					.println("--------------------------------------------------------------------");
			if (inputFile != null) {
				System.out.println("* Input File : "
						+ inputFile.getAbsolutePath());
			}
			if (outputFile != null) {
				System.out.println("* output File : "
						+ outputFile.getAbsolutePath());
			}

			if (isOutput) {
				output = new BufferedWriter(new FileWriter(outputFile));
				output.append("CLIB Info: (" + now + ")");
				output.newLine();
				output.append("---------------------------------------------------------------------");
				output.newLine();
				output.append("* EAP Server IP : " + defaultControllerHost
						+ ":" + defaultControllerPort);
				output.newLine();
				output.append("* User name : " + user);
				output.newLine();
				output.append("* Period : " + periodSec + " Sec");
				output.newLine();
				output.append("* Total Cycle : " + executeCount);
				output.newLine();
				output.append("* Execute CLI Commands Count: "
						+ commands.size());
				output.newLine();
				output.append("=======================Each Command=================================");
				output.newLine();
				for (String command : commands) {
					output.append(command);
					output.newLine();
				}
				output.append("=======================Each Command=================================");
				output.newLine();
				output.append("--------------------------------------------------------------------");
				output.newLine();
				if (inputFile != null) {
					output.append("* Input File : "
							+ inputFile.getAbsolutePath());
					output.newLine();
				}
				if (outputFile != null) {
					output.append("* output File : "
							+ outputFile.getAbsolutePath());
					output.newLine();
				}
			}

			if (commands != null) {
				System.out.println(defaultControllerHost );
				System.out.println(defaultControllerPort );
				System.out.println(user );
				System.out.println( password);
				cmdCtx = initCommandContext(defaultControllerHost,
						defaultControllerPort, user, password);
				int count = 0;

				while (count <= executeCount) {
					processCommands(commands, cmdCtx, output);
					count++;
					Thread.sleep(periodSec * 1000);
				}
			}
		} catch (Throwable t) {
			t.printStackTrace();
			exitCode = 1;
		} finally {
			if (cmdCtx != null && cmdCtx.getExitCode() != 0) {
				exitCode = cmdCtx.getExitCode();
				cmdCtx.disconnectController();
			}
			if (cmdCtx != null ) cmdCtx.terminateSession();
			if (isOutput) {
				output.close();
			}
			if (baos != null) {
				baos.close();
				// System.out.println("C:/Users/Arthur/Dropbox/Arthur/wsElegance/client_demo/"+fileName);
				// File df = new
				// File("C:/Users/Arthur/Dropbox/Arthur/wsElegance/client_demo/"+fileName);
				// System.out.println("刪除檔案是否成功："+ df.delete());
			}
		}
		System.exit(exitCode);
	}

	private static CommandContext initCommandContext(String defaultHost,
			int defaultPort, String username, char[] password)
			throws CliInitializationException {
		final CommandContext cmdCtx = CommandContextFactory
				.getInstance()
				.newCommandContext(defaultHost, defaultPort, username, password);

		try {
			System.out.println("Action : Connecting to EAP Server...");
			cmdCtx.connectController();
			cmdCtx.handle("connect");
			System.out.println("Result : Success to EAP Server");
		} catch (CommandLineException e) {
			throw new CliInitializationException(
					"Failed to connect to the controller", e);
		}

		return cmdCtx;
	}

	private static void processCommands(List<String> commands,
			CommandContext cmdCtx, BufferedWriter output)
			throws CommandLineException, IOException {
		int i = 0;
		ModelControllerClient client = cmdCtx.getModelControllerClient();
		ModelNode requestNode = null;
		ModelNode result = null;
		Date now = new Date();
		SimpleDateFormat simpleDataFormat = new SimpleDateFormat("HH:mm:ss");

		try {
			while (cmdCtx.getExitCode() == 0 && i < commands.size()
					&& !cmdCtx.isTerminated()) {
				System.out.println("Executing : " + commands.get(i)
						+ " Date : " + simpleDataFormat.format(now));
				requestNode = cmdCtx.buildRequest(commands.get(i));
				result = client.execute(requestNode);
				System.out.println(">>Result : " + result.get("result"));
				if (output != null) {
					output.append("Executing : " + commands.get(i) + " Date : "
							+ simpleDataFormat.format(now));
					output.newLine();
					output.append(">>Result : "
							+ result.get("result").toString());
					output.newLine();
					output.flush();
				}
				//output.newLine();
				//output.flush();
				++i;
			}

		} catch (CommandFormatException e) {
			throw new CommandLineException("Command format is not supported", e);

		} catch (IOException e) {
			throw new IOException("No Response from Server");

		}
	}

	private static List<String> processFile(File file,
			final CommandContext cmdCtx) {

		BufferedReader reader = null;
		List<String> resultCommands = new ArrayList<String>();
		try {
			reader = new BufferedReader(new FileReader(file));
			String line = reader.readLine();
			while (line != null) {
				resultCommands.add(line);
				line = reader.readLine();
			}
		} catch (Throwable e) {
			throw new IllegalStateException("Failed to process file '"
					+ file.getAbsolutePath() + "'", e);
		} finally {
			StreamUtils.safeClose(reader);
		}

		return resultCommands;
	}

}